home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1995 March / Macworld CD-ROM (March 1995).cdr / Updaters / Symantec C++ 6.0.1 Update / Library Updates / Standard Libraries / C sources / atexit.c next >
Encoding:
C/C++ Source or Header  |  1993-08-02  |  5.2 KB  |  336 lines  |  [TEXT/KAHL]

  1.  
  2. /*
  3.  *  atexit.c
  4.  *
  5.  *  Copyright (c) 1993 Symantec Corporation.  All rights reserved.
  6.  *
  7.  */
  8.  
  9. #include <MacHeaders>
  10.  
  11. #include "stdlib.h"
  12. #include "stdio.h"
  13. #include "ansi_private.h"
  14.  
  15.  
  16. #define MAXEXIT            32
  17.  
  18. /*
  19.  *  There are slots for MAXEXIT+2 shutdown routines:
  20.  *
  21.  *        0                reserved for stdio shutdown
  22.  *        1                reserved for console shutdown
  23.  *        2 .. MAXEXIT+1    available for user shutdown routines
  24.  *
  25.  *  The routines will be called in descending slot order.  Therefore,
  26.  *  the console shutdown routine (if any) and the stdio shutdown routine
  27.  *  (if any) are always called last.
  28.  *
  29.  *  Shutdown routines installed with "atexit" (including the stdio and
  30.  *  console shutdown routines) are called only on normal termination, i.e.
  31.  *  calling "exit" or returning from "main".
  32.  *
  33.  *  Shutdown routines installed with "_atexit" are called on "ExitToShell"
  34.  *  as well as on normal termination.
  35.  *
  36.  *  When initiating any other form of termination (e.g. "Launch"), the
  37.  *  user can call "_exiting" to force shutdown routines to be called.
  38.  *
  39.  */
  40.  
  41. int _abnormal_exit;
  42.  
  43. static struct proc {
  44.     __exit_func        proc;        /*  non-zero -> shutdown routine  */
  45.     short            always;        /*  false -> call only on normal exit  */
  46. } exitproc[MAXEXIT + 2];
  47.  
  48. static int next = 2;
  49. static __exit_func oldexit, oldES;
  50. static void *ptrES;
  51.  
  52. static void normal_exit(void);
  53. static void newES(void);
  54. static void nop(void);
  55.  
  56. #pragma parameter A0 get_vector
  57. static __exit_func get_vector(void) = { 0x206D, 0x006C };    /*  "MOVEA.L 0x6C(A5),A0"  */
  58.  
  59. #pragma parameter set_vector(A0)
  60. static void set_vector(__exit_func) = { 0x2B48, 0x006C };    /*  "MOVE.L  A0,0x6C(A5)"  */
  61.  
  62. static void RememberA5(void);
  63. static long GetCurrentA5(void);
  64.  
  65.  
  66. /*
  67.  *  atexit - install user shutdown routine
  68.  *
  69.  */
  70.  
  71. int
  72. atexit(__exit_func proc)
  73. {
  74.     register struct proc *p;
  75.  
  76.     if (next > MAXEXIT + 1)
  77.         return(-1);
  78.         
  79.         /*  install proc in table  */
  80.             
  81.     p = &exitproc[next++];
  82.     p->proc = proc;
  83. /*    p->always = 0;    */
  84.  
  85.         /*  install exit vector  */
  86.  
  87.     RememberA5();
  88.     if (!oldexit) {
  89.         oldexit = get_vector();
  90.         set_vector(normal_exit);
  91.     }
  92.     return(0);
  93. }
  94.  
  95.  
  96. /*
  97.  *  _atexit - install a critical shutdown routine
  98.  *
  99.  *  Routines installed with "_atexit" are called even if the program does
  100.  *  not terminate normally, provided only that "ExitToShell" is called.
  101.  *
  102.  */
  103.  
  104. int
  105. _atexit(__exit_func proc)
  106. {
  107.     register struct proc *p;
  108.     register struct { short jmp; __exit_func proc; } *q;
  109.     
  110.     if (next > MAXEXIT + 1)
  111.         return(-1);
  112.         
  113.         /*  install proc in table  */
  114.             
  115.     p = &exitproc[next++];
  116.     p->proc = proc;
  117.     p->always = 1;
  118.     
  119.         /*  install ExitToShell hook  */
  120.  
  121.     RememberA5();
  122.     if (!oldES) {
  123.         oldES = (__exit_func) GetTrapAddress(0xA9F4);
  124.         if (ROM85 >= 0)
  125.             SetTrapAddress((long) newES, 0xA9F4);
  126.         else {
  127.             q = (void *) NewPtrSys(sizeof *q);
  128.             q->jmp = 0x4EF9;
  129.             q->proc = newES;
  130.             SetTrapAddress((long) (ptrES = q), 0xA9F4);
  131.         }
  132.     }
  133.     return(0);
  134. }
  135.  
  136.  
  137. /*
  138.  *  __atexit_console - install console shutdown routine
  139.  *
  140.  *  This is called when a console window is opened.
  141.  *
  142.  */
  143.  
  144. void
  145. __atexit_console(__exit_func proc)
  146. {
  147.     int save = next;
  148.     
  149.     next = 1;
  150.     atexit(proc);
  151.     next = save;
  152. }
  153.  
  154.  
  155. /*
  156.  *  __atexit_stdio - install stdio shutdown routine
  157.  *
  158.  *  This is called when stdio opens a file.
  159.  *
  160.  */
  161.  
  162. void
  163. __atexit_stdio(__exit_func proc)
  164. {
  165.     int save = next;
  166.     
  167.     next = 0;
  168.     _atexit(proc);
  169.     next = save;
  170. }
  171.  
  172.  
  173. /*
  174.  *  exit - normal program termination
  175.  *
  176.  *  The exit status is ignored.
  177.  *
  178.  */
  179.  
  180. void
  181. exit(int i)
  182. {
  183.     (*get_vector())();
  184.     ExitToShell();
  185. }
  186.  
  187.  
  188. /*
  189.  *  _exit - abnormal program termination
  190.  *
  191.  *  The exit status is ignored.
  192.  *
  193.  */
  194.  
  195. void
  196. _exit(int i)
  197. {
  198.     ExitToShell();
  199. }
  200.  
  201.  
  202. /*
  203.  *  normal_exit - atexit vector
  204.  *
  205.  */
  206.  
  207. static void
  208. normal_exit(void)
  209. {
  210.     _exiting(1);
  211. }
  212.  
  213.  
  214. /*
  215.  *  newES - ExitToShell intercept
  216.  *
  217.  */
  218.  
  219. static void
  220. newES(void)
  221. {
  222.     _exiting(0);
  223.     ExitToShell();
  224. }
  225.  
  226.  
  227. /*
  228.  *  _exiting - perform shutdown activity
  229.  *
  230.  *  The argument controls which shutdown routines should be called:
  231.  *
  232.  *        _exiting(1)        call all installed shutdown routines
  233.  *        _exiting(0)        call only routines installed with "_atexit"
  234.  *
  235.  */
  236.  
  237. void
  238. _exiting(int normally)
  239. {
  240.     register struct proc *p = &exitproc[MAXEXIT + 2];
  241.     __exit_func proc;
  242.     int i;
  243.     long oldA5 = GetCurrentA5();
  244.  
  245.     if(oldA5)
  246.         SetA5(GetCurrentA5());
  247.     
  248.         /*  call installed routines  */
  249.     
  250.     if (!normally)
  251.         _abnormal_exit = 1;
  252.     p = &exitproc[MAXEXIT + 2];
  253.     for (i = MAXEXIT + 2; i--; ) {
  254.         if (proc = (--p)->proc) {
  255.             p->proc = 0;
  256.             if (normally || p->always)
  257.                 (*proc)();
  258.         }
  259.     }
  260.     
  261.         /*  deallocate ExitToShell intercept  */
  262.     
  263.     if (ptrES) {
  264.         DisposePtr(ptrES);
  265.         ptrES = 0;
  266.     }
  267.  
  268.         /*  remove ExitToShell intercept  */
  269.     
  270.     if (oldES) {
  271.         SetTrapAddress((long) oldES, 0xA9F4);
  272.         oldES = 0;
  273.     }
  274.  
  275.         /*  call original exit proc  */
  276.  
  277.     if (oldexit)
  278.         (*oldexit)();
  279.     else
  280.         (*get_vector())();
  281.     oldexit = nop;
  282.     if(oldA5)
  283.         SetA5(oldA5);
  284. }
  285.  
  286.  
  287. /*
  288.  *  nop - do nothing
  289.  *
  290.  */
  291.  
  292. static void
  293. nop(void)
  294. {
  295. }
  296.  
  297.  
  298. /*
  299.  *  __GetA5 - get pointer to PC-relative location in which to store our A5
  300.  *
  301.  */
  302.  
  303. static void
  304. __GetA5(void)
  305. {
  306.     asm {
  307.         bsr.s    @1
  308.         dc.l    0            ;  store A4 here
  309. @1        move.l    (sp)+,a1
  310.     }
  311. }
  312.  
  313.  
  314. /*
  315.  *  RememberA5 - remember our A5 in a PC-relative location
  316.  *
  317.  */
  318.  
  319. static void
  320. RememberA5(void)
  321. {
  322.     __GetA5(); asm { move.l    a5,(a1) }
  323. }
  324.  
  325.  
  326. /*
  327.  *  GetCurrentA5 - obtain our A5 from its PC-relative location
  328.  *
  329.  */
  330.  
  331. static long
  332. GetCurrentA5(void)
  333. {
  334.     __GetA5(); asm { move.l    (a1),d0 }
  335. }
  336.